#ifndef _SHADER_HPP
#define _SHADER_HPP
#include <cstdio>
#include <cstring>
#include <cstdlib>

struct shader_util {
	static GLuint 
	loadshader(const char *filename, GLenum shadertype) {
		FILE *file = fopen(filename, "rb");
		if (file == NULL) {
			printf("fail to open file:%s\n", filename);
			return 0;
		}

		fpos_t beginpos;
		fgetpos(file, &beginpos);

		fseek(file, 0, SEEK_END);
	  	long size = ftell(file); // get file size
	  	fsetpos(file, &beginpos);

	  	int len = (int)(size + 1); // just plus '\0' for a simple way
	  	char *content = (char*)malloc(len);
	  	memset(content, 0, len);
	  	fread(content, len, 1, file); // never use fgets here
	  	fclose(file);

	  	// printf("content:[\n%s]\n", content); // just debug
	  	GLuint shader = glCreateShader(shadertype);
	  	const char *ptr = (const char *)content;
	  	glShaderSource(shader, 1, &ptr, NULL);
	  	free(content);

	  	glCompileShader(shader);

	  	GLint result, loglen;
	  	glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
	  	glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &loglen);
	  	printf("compile shader status, result:%d loglen:%d\n", result, loglen);
	  	if (loglen > 1) {
	  		GLchar log[loglen];
	  		glGetShaderInfoLog(shader, loglen, NULL, log);
	  		printf("compile shader log:[%s]\n", log);
	  	}

	  	if (result == GL_FALSE) {
	  		glDeleteShader(shader);
	  		shader = 0;
	  		printf("fail to compile shader\n");
	  	}
		return shader;
	}

	static GLuint 
	linkprogram(const char *vertexfile, const char *fragmentfile) {
		GLuint vertexshader = loadshader(vertexfile, GL_VERTEX_SHADER);
		GLuint fragmentshader = loadshader(fragmentfile, GL_FRAGMENT_SHADER);
		if (vertexshader == 0 || fragmentshader == 0) {
			printf("link program but invalid shader");
			return 0;
		}

		GLuint program = 0;
		program = glCreateProgram();
		glAttachShader(program, vertexshader);
		glAttachShader(program, fragmentshader);
		glLinkProgram(program);

		GLint result, loglen;
		glGetProgramiv(program, GL_LINK_STATUS, &result);
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &loglen);
		printf("link program status, result:%d, loglen:%d\n", result, loglen);
		if (loglen > 1) {
			GLchar log[loglen];
			glGetProgramInfoLog(program, loglen, NULL, log);
			printf("link program log:[%s]\n", log);
		}

		glDetachShader(program, vertexshader);
		glDetachShader(program, fragmentshader);
		glDeleteShader(vertexshader);
		glDeleteShader(fragmentshader);
		printf("delete attached shader after link\n");

		if (result == GL_FALSE) {
			glDeleteProgram(program);
			program = 0;
			printf("fail to link program\n");
		}
		printf("link program successfully\n");
		return program;
	}
};

#endif
